package com.ysd.shopcar.common;

import com.google.common.collect.Lists;
import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.MDC;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 对象工具
 */
@Log
public class BaseUtils {

	public static final Field[] NO_FIELDS = {};
	/**
	 * Cache for {@link Class#getDeclaredFields()}, allowing for fast iteration.
	 */
	public static final Map<Class<?>, Field[]> declaredFieldsCache = new ConcurrentReferenceHashMap<Class<?>, Field[]>(
			256);

	/**
	 * 判断列表是否为空
	 */
	public static boolean listNotEmptyAndNull(List<?> list) {
		if(list != null && list.size() > 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * 是否非空
	 */
	public static boolean isNotNull(Object object) {
		if (object == null) {
			return false;
		}
		return true;
	}

	/**
	 * 是否非空
	 */
	public static boolean isNotNull(String object) {
		if (StringUtils.isBlank(object)) {
			return false;
		}
		return true;
	}

	/**
	 * 是否非空
	 */
	public static boolean isNotNull(List<?> object) {
		if (object == null || object.size() == 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否非空
	 */
	public static boolean isNotNull(Map<?, ?> object) {
		if (object == null || object.size() == 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否非空
	 */
	public static boolean isNotNull(Set<?> object) {
		if (object == null || object.size() == 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是正数
	 */
	public static boolean isPositive(Integer number) {
		if (number == null) {
			return false;
		}
		if (number <= 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是正数
	 */
	public static boolean isPositive(Long number) {
		if (number == null) {
			return false;
		}
		if (number <= 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是正数
	 */
	public static boolean isPositive(Float number) {
		if (number == null) {
			return false;
		}
		if (number <= 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是正数
	 */
	public static boolean isPositive(Double number) {
		if (number == null) {
			return false;
		}
		if (number <= 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是正数
	 */
	public static boolean isPositive(BigDecimal number) {
		if (number == null) {
			return false;
		}
		if (number.compareTo(BigDecimal.ZERO) <= 0) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是正数
	 */
	public static boolean isPositive(String number) {
		if (StringUtils.isBlank(number)) {
			return false;
		}
		try {
			if (new BigDecimal(number).compareTo(BigDecimal.ZERO) <= 0) {
				return false;
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是整数
	 */
	public static boolean isInteger(String number) {
		if (StringUtils.isBlank(number)) {
			return false;
		}
		try {
			Integer.valueOf(number);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * 是否是长整数
	 */
	public static boolean isLong(String number) {
		if (StringUtils.isBlank(number)) {
			return false;
		}
		try {
			 Long.valueOf(number);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * 字符串转long
	 */
	public static long toLong(String number) {
		if (StringUtils.isBlank(number)) {
			return BigDecimal.ZERO.longValue();
		}
		try {
			return new BigDecimal(number.trim()).longValue();
		} catch (Exception e) {
			return BigDecimal.ZERO.longValue();
		}
	}

	/**
	 * 字符串转double
	 */
	public static long toLong(Long number) {
		if (number == null) {
			return BigDecimal.ZERO.longValue();
		}
		return number.longValue();
	}

	/**
	 * 字符串转double
	 */
	public static double toDouble(String number) {
		if (StringUtils.isBlank(number)) {
			return BigDecimal.ZERO.doubleValue();
		}
		try {
			return new BigDecimal(number.trim()).doubleValue();
		} catch (Exception e) {
			return BigDecimal.ZERO.doubleValue();
		}
	}

	/**
	 * 字符串转double
	 */
	public static double toDouble(Double number) {
		if (number == null) {
			return BigDecimal.ZERO.doubleValue();
		}
		return number.doubleValue();
	}

	/**
	 * 字符串转double
	 */
	public static float toFloat(String number) {
		if (StringUtils.isBlank(number)) {
			return BigDecimal.ZERO.floatValue();
		}
		try {
			return new BigDecimal(number.trim()).floatValue();
		} catch (Exception e) {
			return BigDecimal.ZERO.floatValue();
		}
	}

	/**
	 * 字符串转double
	 */
	public static float toFloat(Float number) {
		if (number == null) {
			return BigDecimal.ZERO.floatValue();
		}
		return number.floatValue();
	}
	/**
	 * int转double
	 */
	public static float toFloat(int number) {

		try {
			return new BigDecimal(number).floatValue();
		} catch (Exception e) {
			return BigDecimal.ZERO.floatValue();
		}
	}

	/**
	 * 字符串转int
	 */
	public static int toInt(String number) {
		if (StringUtils.isBlank(number)) {
			return BigDecimal.ZERO.intValue();
		}
		try {
			return new BigDecimal(number.trim()).intValue();
		} catch (Exception e) {
			return BigDecimal.ZERO.intValue();
		}
	}

	/**
	 * 字符串转int
	 */
	public static int toInt(Integer number) {
		if (number == null) {
			return BigDecimal.ZERO.intValue();
		}
		return number.intValue();
	}

	/**
	 * 同类型对象转list,并去空
	 */
	public static <T> List<T> toList(T ... datas){
		List<T> dataList = Lists.newArrayList();
		if (datas == null){
			return dataList;
		}
		for (T data : datas){
			if (isNotNull(data)){}{
				dataList.add(data);
			}
		}
		return dataList;
	}

	/**
	 * This variant retrieves {@link Class#getDeclaredFields()} from a local cache in order to avoid the JVM's SecurityManager check and defensive array
	 * copying.
	 */
	public static Field[] getDeclaredFields(Class<?> clazz) {
		Assert.notNull(clazz, "Class must not be null");
		Field[] result = declaredFieldsCache.get(clazz);
		if (result == null) {
			result = clazz.getDeclaredFields();
			declaredFieldsCache.put(clazz, (result.length == 0 ? NO_FIELDS : result));
		}
		return result;
	}

	/**
	 * 将对象String类型的Field做trim操作，不支持对象的对象
	 */
	public static void trim(Object... objects) {
		if (objects == null || objects.length == 0) {
			return;
		}
		for (Object object : objects) {
			if (object == null) {
				return;
			}
			Field[] fields = getDeclaredFields(object.getClass());
			for (Field field : fields) {
				if (field.getType() == String.class) {
					field.setAccessible(true);
					String fieldValue;
					try {
						fieldValue = (String) field.get(object);
						if (fieldValue == null)
							continue;
						field.set(object, StringUtils.trim(fieldValue));
					} catch (IllegalArgumentException | IllegalAccessException e) {
						log.warning("tTrim异常:" + ExceptionUtils.getStackTrace(e));
					}
				}
			}
		}
	}

	/**
	 * 金额格式化，保留2为小数
	 *
	 * @param fen 分
	 */
	public static String formatYuanFromFen(Integer fen) {
		BigDecimal result = null;
		if (fen == null) {
			result = BigDecimal.ZERO;
		} else {
			result = BigDecimal.valueOf(fen).divide(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_DOWN);
		}
		return new DecimalFormat("0.00").format(result);
	}

	/**
	 * 金额格式化，保留2为小数
	 *
	 * @param yuan 元
	 */
	public static String formatYuan(String yuan) {
		BigDecimal result = null;
		if (StringUtils.isBlank(yuan)) {
			result = BigDecimal.ZERO;
		} else {
			result = new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_DOWN);
		}
		return new DecimalFormat("0.00").format(result);
	}

	/**
	 * 金额格式化，保留2为小数
	 *
	 * @param yuan 元
	 */
	public static String formatYuan(BigDecimal yuan) {
		BigDecimal result = null;
		if (yuan == null) {
			result = BigDecimal.ZERO;
		} else {
			result = yuan.setScale(2, BigDecimal.ROUND_DOWN);
		}
		return new DecimalFormat("0.00").format(result);
	}

	/**
	 * 金额格式化，保留2为小数
	 *
	 * @param yuan 元
	 */
	public static String formatYuan(Double yuan) {
		BigDecimal result = null;
		if (yuan == null) {
			result = BigDecimal.ZERO;
		} else {
			result = new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP);
		}
		return new DecimalFormat("0.00").format(result);
	}

	/**
	 * 验证非空
	 */
	public static void verifyNotNull(Object object, String message) {
		if (!BaseUtils.isNotNull(object)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证非空
	 */
	public static void verifyNotNull(String object, String message) {
		if (!BaseUtils.isNotNull(object)) {
			throw new IllegalArgumentException(message);
		}
	}
	
	/**
	 * 验证非空
	 */
	public static void verifyNotNull(List<?> list, String message) {
		if (!BaseUtils.listNotEmptyAndNull(list)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证正数
	 */
	public static void verifyPositive(Integer number, String message) {
		if (!BaseUtils.isPositive(number)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证正数
	 */
	public static void verifyPositive(Long number, String message) {
		if (!BaseUtils.isPositive(number)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证正数
	 */
	public static void verifyPositive(Float number, String message) {
		if (!BaseUtils.isPositive(number)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证正数
	 */
	public static void verifyPositive(Double number, String message) {
		if (!BaseUtils.isPositive(number)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证正数
	 *
	 * @param number
	 * @param message
	 */
	public static void verifyPositive(String number, String message) {
		if (!BaseUtils.isPositive(number)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 验证枚举
	 *
	 * @param
	 * @param message
	 */
	public static <T> void verifyEnum(List<T> list, T t, String message) {
		if (list == null || list.size() == 0 || t == null) {
			throw new IllegalArgumentException(message);
		}
		if (!list.contains(t)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 判断是否是时间戳
	 *
	 * @param value
	 * @return
	 */
	public static boolean isTimestamp(String value) {
		boolean result = false;
		if (StringUtils.isBlank(value) || value.length() != 13) {
			return result;
		}
		try {
			Long.parseLong(value);
			result = true;
		} catch (Exception ex) {
			result = false;
		}
		return result;
	}

	/**
	 * 校验时间
	 *
	 * @param value
	 * @param message
	 */
	public static void verifyTime(String value, String message) {
		if (!isTimestamp(value)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 校验时间
	 */
	public static void verifyTime(Long value, String message) {
		if (!isPositive(value)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 判断经纬度是否有效
	 */
	public static boolean isEffectLatLon(String value) {
		boolean result = false;
		if (StringUtils.isBlank(value)) {
			return result;
		}
		if (value.matches("\\d{1,3}\\.\\d{1,15}") == false) {
			return result;
		}
		try {
			Double dValue = Double.valueOf(value);
			if (dValue > 180 || dValue < -180) {
				return result;
			}
			result = true;
		} catch (Exception ex) {
			result = false;
		}
		return result;
	}

	/**
	 * 校验经纬度
	 */
	public static void verifyLatLon(String value, String message) {
		if (!BaseUtils.isEffectLatLon(value)) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 设置日志title
	 */
	public static void putLogTitle(String logTitle) {
		MDC.put("title", logTitle);
	}

	/**
	 * 设置日志Tag
	 */
	public static void putLogTag(String key, String value) {
		if(StringUtils.isNotBlank(value)){
			MDC.put(key, value);
		}
	}

	/**
	 * 获取计算结果
	 */
	public static <T> T getFuture(String message, Future<T> future) {
		try {
			return future.get(8, TimeUnit.SECONDS);
		} catch (Exception e) {
			log.warning(message + "超时");
		}
		return null;
	}

	/**
	 * 获取异步结果
	 */
	public static <T> List<T> getFuture(String message, List<Future<T>> futures) {
		if (futures == null || futures.size() == 0) {
			return null;
		}
		List<T> result = Lists.newArrayList();
		for (Future<T> future : futures) {
			try {
				T temp = future.get(8, TimeUnit.SECONDS);
				if (temp != null) {
					result.add(temp);
				}
			} catch (Exception e) {
				log.warning(message + "超时");
			}
		}
		return result;
	}

	/**
	 * 获取异步结果
	 */
	public static <T> List<T> getFuture(String message, Long timeout, List<Future<T>> futures) {
		if (futures == null || futures.size() == 0) {
			return null;
		}
		List<T> result = Lists.newArrayList();
		for (Future<T> future : futures) {
			try {
				T temp = future.get(timeout, TimeUnit.SECONDS);
				if (temp != null) {
					result.add(temp);
				}
			} catch (Exception e) {
				log.warning(message + "超时");
			}
		}
		return result;
	}

	/**
	 *	表达式校验
	 */
	public static void checkExpressionIsTrue(boolean expression, String errorMessage) {
		if (!expression) {
			throw new IllegalArgumentException(errorMessage);
		}
	}

	/**
	 * 去空格
	 */
	public static String safeTrim(String object) {
		if (object == null) {
			return object;
		}
		return object.trim();
	}

	/**
	 * 判断是否是float类型
	 */
	public static boolean vaildFloatValue(Float value) {
		if (value != null && value.compareTo(Float.valueOf(0)) > 0) {
			return true;
		}
		return false;
	}

	/**
	 * 利用BigDecimal相乘
	 */
	public static BigDecimal multiply(String multiplicand, BigDecimal multiplier) {
		if (StringUtils.isBlank(multiplicand) || multiplier == null) {
			return BigDecimal.ZERO;
		}
		try {
			return multiplier.multiply(new BigDecimal(multiplicand.trim()));
		} catch (Exception e) {
			return BigDecimal.ZERO;
		}
	}

	/**
	 * 利用BigDecimal相除
	 */
	public static BigDecimal divide(String dividend, BigDecimal divisor, int scale) {
		if (StringUtils.isBlank(dividend) || divisor == null) {
			return BigDecimal.ZERO;
		}
		try {
			BigDecimal result = new BigDecimal(dividend.trim()).divide(divisor, scale, BigDecimal.ROUND_UP);
			return result.stripTrailingZeros();
		} catch (Exception e) {
			return BigDecimal.ZERO;
		}
	}

	/**
	 * 利用BigDecimal相除
	 */
	public static BigDecimal divide(String dividend, BigDecimal divisor) {
		if (StringUtils.isBlank(dividend) || divisor == null) {
			return BigDecimal.ZERO;
		}
		try {
			return new BigDecimal(dividend.trim()).divide(divisor);
		} catch (Exception e) {
			return BigDecimal.ZERO;
		}
	}

	/**
	 * 打印日志
	 */
	public static void logSoa(String client, String method, long elapsed, String requestBody, String responseBody) {
		StringBuilder sb = new StringBuilder();
		sb.append("SOA客户端：").append(client);
		sb.append(BaseConst.NEW_LINE).append("SOA方法：").append(method);
		sb.append(BaseConst.NEW_LINE).append("耗时：").append(elapsed).append("毫秒");
		if (org.apache.commons.lang.StringUtils.isNotBlank(requestBody)) {
			sb.append(BaseConst.NEW_LINE).append("请求：").append(requestBody);
		}
		sb.append(BaseConst.NEW_LINE).append("响应：").append(responseBody);
		log.info(sb.toString());
	}
}